package HttpWsUtils

import (
	"dgo/goutils/utils"
	"fmt"
	"github.com/gorilla/websocket"
	"net/http"
	"time"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  10240,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}
var (
	WsSc                *utils.SubscribeCenter = utils.NewSubscribeCenter()
	WsConnOnAcceptEvent func(wsconn *WsConnWrapper) bool
	WsConnOnCloseEvent  func(wsconn *WsConnWrapper)
	WsConnOnRecvEvent   func(wsconn *WsConnWrapper, msgtype int, msg []byte)
)

type WsEvent func(wsconn *WsConnWrapper)

type WsConnWrapper struct {
	conn           *websocket.Conn
	W              http.ResponseWriter
	R              *http.Request
	closeEventList *utils.SyncQueue
	TagPtr         interface{}
}

func NewWsConnWrapper(conn *websocket.Conn, w http.ResponseWriter, r *http.Request) *WsConnWrapper {
	rval := &WsConnWrapper{conn: conn,
		W: w, R: r,
		closeEventList: utils.NewSyncQueue(),
	}
	rval.conn.SetCloseHandler(rval.onClose)
	return rval
}

func (this *WsConnWrapper) QryParamAsString(key string) string {
	v := this.R.URL.Query().Get(key)

	if len(v) == 0 {
		v = this.R.FormValue(key)
	}
	return v
}

func (this *WsConnWrapper) RemoteAddr() string {
	return this.conn.RemoteAddr().String()
}

func (this *WsConnWrapper) onClose(code int, text string) error {
	this.closeEventList.Range(func(idx int, value interface{}, removeit *bool) bool {
		if value != nil {
			if cb, ok := value.(WsEvent); ok {
				cb(this)
			}
		}
		return true
	})

	if WsConnOnCloseEvent != nil { // ! 响应全局事件
		WsConnOnCloseEvent(this)
	}
	return nil
}

func (this *WsConnWrapper) onRecv(msgtype int, buf []byte) error {
	if WsConnOnRecvEvent != nil { // ! 响应全局事件
		WsConnOnRecvEvent(this, msgtype, buf)
	}
	return nil
}

func (this *WsConnWrapper) SendMsg(data interface{}) error {
	if str, ok := data.(string); ok {
		this.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
		return this.conn.WriteMessage(websocket.TextMessage, []byte(str))
	}

	if buf, ok := data.([]byte); ok {
		this.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
		return this.conn.WriteMessage(websocket.BinaryMessage, buf)
	}

	str := fmt.Sprintf("%v", data)
	this.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
	return this.conn.WriteMessage(websocket.TextMessage, []byte(str))
}

func (this *WsConnWrapper) AddCloseListener(event WsEvent) {
	this.closeEventList.Push(event)
}

func (this *WsConnWrapper) ResponseAsJSON(kvPairs ...interface{}) {
	if len(kvPairs) == 1 {
		if str, ok := kvPairs[0].(string); ok {
			this.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
			this.conn.WriteMessage(websocket.TextMessage, []byte(str))
		} else if buf, ok := kvPairs[0].([]byte); ok {
			this.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
			this.conn.WriteMessage(websocket.TextMessage, buf)
		}
		return
	}
	var jb utils.JSONBuilder
	jb.AddObjectEx(jb.EscapeSimpleVal, kvPairs...)
	this.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
	this.conn.WriteMessage(websocket.TextMessage, jb.Bytes())
}

/*
订阅发送信息通道, 像WsSc通道发送信息, 将会发送消息到

	可以多次订阅
*/
func (this *WsConnWrapper) SubSendChannel(channelKey string) {
	WsSc.SubscribeChannel(channelKey, this.conn,
		func(sender interface{}, channelid string, subscribeid interface{}, data interface{}, tag interface{}, isBreak *bool) bool {
			if str, ok := data.(string); ok {
				this.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
				this.conn.WriteMessage(websocket.TextMessage, []byte(str))
				return true
			}

			if buf, ok := data.([]byte); ok {
				this.conn.SetWriteDeadline(time.Now().Add(time.Second * 10))
				this.conn.WriteMessage(websocket.TextMessage, buf)
				return true
			}
			return false
		})
	this.AddCloseListener(func(wsconn *WsConnWrapper) {
		WsSc.UnsubscribeChannel(channelKey, this.conn)
	})
}
